# 题目: 437. 路径总和 III
给定一个二叉树的根节点 root
,和一个整数 targetSum
,求该二叉树里节点值之和等于 targetSum
的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
# 示例1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
# 示例2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
# 提示
- 二叉树的节点个数的范围是 [0,1000]
<= Node.val <=-1000 <= targetSum <= 1000
# 题解: 穷举 深度优先搜索
因为 路径 必须是向下的, 即只能从父节点到子节点,我们可以借助递归遍历来得到 当前节点 到 以递归节点的 totalNum,通过判断 tatolNum 与 targetNum 值 来增加路径总数,并且返回路径总数。
我们递归遍历每一个节点的所有可能的路径,然后将这些路径数目加起来即为返回结果。
首先定义 targetNum
的路径数目。我们对二叉树上每个节点 p 求出
# 细节
我们对节点 p 求
假设当前的节点 p 的值为
- 对节点 p 的左孩子节点
求出 - 对节点 p 的右孩子节点
求出 - 节点 p 的
即等于 与 之和,同时我们还需要判断一下当前节点 p 的值是否刚好等于 。
# 代码
const rootSum = (root, targetNum)=>{
if(root === null) return 0
let ret = 0
if(root.val === targetNum) ret++
ret += rootSum(root.left, targetNum - root.val)
ret += rootSum(root.right, targetNum - root.val)
return ret
}
var pathSum = function(root, targetSum) {
if(root === null) return 0
let ret = rootSum(root,targetSum)
// 递归调用左节点
ret += pathSum(root.left,targetSum)
// 递归调用右节点
ret += pathSum(root.right,targetSum)
return ret
};
# 题解 2: 前缀和 深度优先遍历
题解1的遍历,可以很明显的看出有大量的重复计算,而这些重复计算,在这里可以使用 前缀和 + 回溯 来代替。
我们定义节点的前缀和:从根结点到当前结点的路径上所有节点的和。
# 细节
我们通过先序遍历得到从根节点到当前节点的路径中所有节点的前缀和,在已保存的路径前缀和中查找是否存在前缀和刚好等于当前节点到根节点的前缀和 currcurr
减去
对于空路径我们也需要保存预先处理一下,此时因为空路径不经过任何节点,因此它的前缀和为 0。
假设根节点为
,我们当前刚好访问节点 ,则此时从根节点 到节点 的路径(无重复节点)刚好为 ,此时我们可以已经保存了节点 的前缀和,并且计算出了节点 的前缀和。假设当前从根节点
到节点 的前缀和为 ,则此时我们在已保存的前缀和查找是否存在前缀和刚好等于 。假设从根节点 到节点 的路径中存在节点 到根节点 的前缀和为 ,则节点 到 的路径上所有节点的和一定为 。我们利用深度搜索遍历树,当我们退出当前节点时,我们需要及时更新已经保存的前缀和。
# 代码
var pathSum = function(root, targetSum) {
if(root === null) return 0
let ret = rootSum(root,targetSum)
// 递归调用左节点
ret += pathSum(root.left,targetSum)
// 递归调用右节点
ret += pathSum(root.right,targetSum)
return ret
};
const dfs=(root, prefix, curr, targetSum)=>{
if(root===null) return 0
let ret = 0
curr += root.val
ret = prefix.set()
}